import pandas as pd
import numpy as np
import math
import pickle
import dalex as dx
import lime
X_test = pd.read_csv("X_test_chosen_ones.csv").drop(['Unnamed: 0', 'test set id'], axis=1)
y_test = pd.read_csv("y_test_chosen_ones.csv").drop(['Unnamed: 0', 'test set id'], axis=1)
gbm = pickle.load(open("gbm.pickle", 'rb'))
svm = pickle.load(open("svm.pickle", 'rb'))
rfc = pickle.load(open("rfc.pickle", 'rb'))
gbc = pickle.load(open("gbc.pickle", 'rb'))
Do dalszej analizy wezmę pod uwagę szesnaście ciekawych win:
explainer_gbm = dx.Explainer(gbm, X_test, y_test, label = "XGBoost")
explainer_svm = dx.Explainer(svm, X_test, y_test, label = "Support Vector Machine")
explainer_rfc = dx.Explainer(rfc, X_test, y_test, label = "Random Forest")
explainer_gbc = dx.Explainer(gbc, X_test, y_test, label = "Gradient Boosting")
Preparation of a new explainer is initiated -> data : 16 rows 11 cols -> target variable : Parameter 'y' was a pandas.DataFrame. Converted to a numpy.ndarray. -> target variable : 16 values -> model_class : sklearn.model_selection._search.RandomizedSearchCV (default) -> label : XGBoost -> predict function : <function yhat_proba_default at 0x00000236AB00C9D0> will be used (default) -> predict function : Accepts pandas.DataFrame and numpy.ndarray. -> predicted values : min = 0.151, mean = 0.565, max = 0.923 -> model type : classification will be used (default) -> residual function : difference between y and yhat (default) -> residuals : min = -0.894, mean = -0.0651, max = 0.849 -> model_info : package sklearn A new explainer has been created! Preparation of a new explainer is initiated -> data : 16 rows 11 cols -> target variable : Parameter 'y' was a pandas.DataFrame. Converted to a numpy.ndarray. -> target variable : 16 values -> model_class : sklearn.model_selection._search.GridSearchCV (default) -> label : Support Vector Machine -> predict function : <function yhat_default at 0x00000236AB00C940> will be used (default) -> predict function : Accepts pandas.DataFrame and numpy.ndarray. -> predicted values : min = 0.0, mean = 0.5, max = 1.0 -> model type : classification will be used (default) -> residual function : difference between y and yhat (default) -> residuals : min = -1.0, mean = 0.0, max = 1.0 -> model_info : package sklearn A new explainer has been created! Preparation of a new explainer is initiated -> data : 16 rows 11 cols -> target variable : Parameter 'y' was a pandas.DataFrame. Converted to a numpy.ndarray. -> target variable : 16 values -> model_class : sklearn.model_selection._search.RandomizedSearchCV (default) -> label : Random Forest -> predict function : <function yhat_proba_default at 0x00000236AB00C9D0> will be used (default) -> predict function : Accepts pandas.DataFrame and numpy.ndarray. -> predicted values : min = 0.246, mean = 0.551, max = 0.898 -> model type : classification will be used (default) -> residual function : difference between y and yhat (default) -> residuals : min = -0.848, mean = -0.0505, max = 0.754 -> model_info : package sklearn A new explainer has been created! Preparation of a new explainer is initiated -> data : 16 rows 11 cols -> target variable : Parameter 'y' was a pandas.DataFrame. Converted to a numpy.ndarray. -> target variable : 16 values -> model_class : sklearn.model_selection._search.GridSearchCV (default) -> label : Gradient Boosting -> predict function : <function yhat_proba_default at 0x00000236AB00C9D0> will be used (default) -> predict function : Accepts pandas.DataFrame and numpy.ndarray. -> predicted values : min = 0.0168, mean = 0.51, max = 0.962 -> model type : classification will be used (default) -> residual function : difference between y and yhat (default) -> residuals : min = -0.93, mean = -0.00993, max = 0.983 -> model_info : package sklearn A new explainer has been created!
pdp_gbm = explainer_gbm.model_profile()
pdp_svm = explainer_svm.model_profile()
pdp_rfc = explainer_rfc.model_profile()
pdp_gbc = explainer_gbc.model_profile()
Calculating ceteris paribus: 100%|█████████████████████████████████████████████████████| 11/11 [00:00<00:00, 42.72it/s] Calculating ceteris paribus: 100%|█████████████████████████████████████████████████████| 11/11 [00:03<00:00, 2.91it/s] Calculating ceteris paribus: 100%|█████████████████████████████████████████████████████| 11/11 [00:24<00:00, 2.26s/it] Calculating ceteris paribus: 100%|█████████████████████████████████████████████████████| 11/11 [00:00<00:00, 53.90it/s]
pdp_gbm.plot([pdp_svm, pdp_rfc, pdp_gbc])
🍷 Porównując wykresy dla poszczególnych zmiennych, zdecydowanie najbardziej w oczu rzuca się Support Vector Machine - mamy tu styczność z najbardziej gwałtownymi skokami i jedynym takim przypadkiem, że niezależnie od wartości mamy styczność zazwyczaj z <łatwo> policzalną liczbą prawdopodobieństw
🍷 Random Forest wydaje się być najmniej wrażliwy na zmianę pojedynczych zmiennych - choć nie w każdym wypadku (patrz: gęstość)
🍷 Nawet biorąc pod uwagę nieregularność i dynamiczność zmienną SVM, nawet gdyby go wygładzić - widać, że stoi za nim zupełnie inna technika
🍷 Na podstawie przynajmniej tych 16 obserwacji, najsrożej wina zdaje się oceniać Gradient Boosting, przychylniej Random Forest, zaś najlepiej XGBoost - nie jest to jednak stała reguła i różnice nie są duże. Obserwacja o tyle ciekawa, że czułem, że właśnie Gradient Boosting i XGBoost będą siebie najbliżej - nie tylko biorąc pod uwagę koncepcje, ale także i jednak najlepszą trafność
🍷 Support Vector Machine niekiedy zawsze daje mniej-więcej tę samą wartość ze względu na zmianę jakiejś zmiennej, ale są też przypadki, że jej turbulencje owocują w największe rozbieżności
🍷 Dla wszystkich modeli zwykle mamy styczność z zasadą większa wartość --> mniej-więcej stale niższa / wyższa predykcja. Wyjątkiem jest jednak chociażby kolumna free sulfur dioxide, gdzie Support Vector Machine uzyskuje największe wartości na środku analizowanego , czy ciekawe wahania Gradient Boostingu dla chlorides. Regułę świetnie za to potwierdzają chociażby kolumny alcohol, sulphates czy total sulfur dioxide
ale_gbm = explainer_gbm.model_profile(type = 'accumulated')
ale_svm = explainer_svm.model_profile(type = 'accumulated')
ale_rfc = explainer_rfc.model_profile(type = 'accumulated')
ale_gbc = explainer_gbc.model_profile(type = 'accumulated')
Calculating ceteris paribus: 100%|█████████████████████████████████████████████████████| 11/11 [00:00<00:00, 65.54it/s] Calculating accumulated dependency: 100%|██████████████████████████████████████████████| 11/11 [00:01<00:00, 6.99it/s] Calculating ceteris paribus: 100%|█████████████████████████████████████████████████████| 11/11 [00:03<00:00, 3.21it/s] Calculating accumulated dependency: 100%|██████████████████████████████████████████████| 11/11 [00:01<00:00, 7.28it/s] Calculating ceteris paribus: 100%|█████████████████████████████████████████████████████| 11/11 [00:19<00:00, 1.79s/it] Calculating accumulated dependency: 100%|██████████████████████████████████████████████| 11/11 [00:01<00:00, 7.42it/s] Calculating ceteris paribus: 100%|█████████████████████████████████████████████████████| 11/11 [00:00<00:00, 43.95it/s] Calculating accumulated dependency: 100%|██████████████████████████████████████████████| 11/11 [00:01<00:00, 6.54it/s]
ale_gbm.plot([ale_svm, ale_rfc, ale_gbc])
🍷 Bez zmian widać największą "skoczność" dla Support Vector Machine
🍷 Często metoda przyjmuje skrajne wartości - albo największe, albo najmniejsze
🍷 Różnice między XGBoost, Random Forest i Gradient Boosting wydają się być jeszcze mniejsze
🍷 To samo tyczy się wariancji wyników
🍷 Dla niektórych predyktorów mamy niemalże niezmienną wartość - patrz: pH czy residual sugar
🍷 Przynajmniej na tych przykładach PDP zdaje się ukazywać więcej zależności i wniosków